package behavioradaptation.reasoner;

import java.util.LinkedList;
import java.util.List;

import planninglanguage.conditions.AttemptLimitCondition;
import planninglanguage.conditions.Condition;
import planninglanguage.conditions.GoldCondition;
import planninglanguage.conditions.OilCondition;
import planninglanguage.conditions.ResearchCondition;
import planninglanguage.conditions.SupplyCondition;
import planninglanguage.conditions.TimeOutCondition;
import planninglanguage.conditions.UnitExistsCondition;
import planninglanguage.conditions.UnitTypeExistsCondition;
import planninglanguage.conditions.WoodCondition;
import planninglanguage.plans.BasicOperatorPlan;
import planninglanguage.plans.BuildBOPlan;
import planninglanguage.plans.Plan;
import trace.Entry;
import trace.Trace;
import base.WargusGameState;
import behavioradaptation.analysisdata.FailedEntryData;
import behavioradaptation.analysisdata.FailureTypes;
import behavioradaptation.analysisdata.PlanFailuresData;

public class PlanFailureTracker {
	public Trace m_trace;
	public PlanFailureTracker(Trace a_trace)
	{
		m_trace = a_trace;
	}
	/*
	 * Find the plan failures 
	 */
	public List<PlanFailuresData> findPlanFailures()
	{
		List<PlanFailuresData> failures = new LinkedList<PlanFailuresData>();
		List <FailedEntryData> entries = findBOfailures(m_trace);
		for(int i=0; i <entries.size(); i++)
		{
			FailedEntryData failentry = (FailedEntryData)entries.get(i);
			Entry e = failentry.m_fentry;
			if(e.evtype == Entry.EventType.fail)
			{	
					Plan p = e.getPlan();
					WargusGameState gamestate = e.getGameState();
					List<Condition> condlistfailed = e.getCondlist();
					List <FailureTypes.m_failuretype> failuretypes = new LinkedList<FailureTypes.m_failuretype>();					
					findfailuretype(gamestate, p, condlistfailed, failuretypes, e.getfailedConditionType(), failentry.m_index);		
					PlanFailuresData pf = new PlanFailuresData(e.getPlan(), failuretypes, gamestate, failentry.m_index);					
					failures.add(pf);
			}											
		}	
		return failures;
	}
	/*
	 * Find all the basic operator failures
	 */
	public List<FailedEntryData> findBOfailures(Trace trace)
	{
		List <FailedEntryData> failedentry = new LinkedList<FailedEntryData>();
		for(int i = 0; i < trace.size(); i++)
		{
			Entry e = trace.get(i);
			if(e.getPlan() instanceof BasicOperatorPlan && e.getEventType() == Entry.EventType.fail)
			{
				FailedEntryData fentry = new FailedEntryData();
				fentry.m_fentry = e;
				fentry.m_index = i;
				failedentry.add(fentry);
			}	
		}	
		return failedentry;
	}
	/*
	 *  find the failure type for a given basic operator failure
	 */
	public void findfailuretype(WargusGameState gamestate, Plan p, List <Condition> condlist, List <FailureTypes.m_failuretype> failuretypes, Trace.FailureConditionType condtype, int index)
	{		
		for(int i=0; i < condlist.size(); i++)
		{
			Condition c = condlist.get(i);
			if(condlist.get(i)instanceof GoldCondition)
				failuretypes.add(FailureTypes.m_failuretype.NOT_ENOUGH_GOLD);
			else if(condlist.get(i) instanceof WoodCondition)
				failuretypes.add(FailureTypes.m_failuretype.NOT_ENOUGH_WOOD);
			else if(condlist.get(i)instanceof OilCondition)
				failuretypes.add(FailureTypes.m_failuretype.NOT_ENOUGH_OIL);
			else if(condlist.get(i) instanceof SupplyCondition)
				failuretypes.add(FailureTypes.m_failuretype.NOT_ENOUGH_FOOD);
			else if(condlist.get(i) instanceof UnitExistsCondition && condtype == Trace.FailureConditionType.ALIVECONDITION)
			{
				if(p instanceof BuildBOPlan)
					failuretypes.add(FailureTypes.m_failuretype.PEASANTKILLED);
				
			}
			else if(condlist.get(i) instanceof UnitTypeExistsCondition && condtype == Trace.FailureConditionType.PRECONDITION)
			{	
				
				UnitTypeExistsCondition ut = (UnitTypeExistsCondition)c;
				if(ut.getUnitType().equals("peasant"))
					failuretypes.add(FailureTypes.m_failuretype.NO_PEASANT);
				else 
				{
					String []bldgs = {"town-hall","keep","castle","great-hall","stronghold","fortress"};
					boolean matched = false;
					for(i=0;i<bldgs.length ;i++) {
						if(ut.getUnitType().equals(bldgs[i]))
						{
							matched = true;
						}	
					}
					if(matched)
						failuretypes.add(FailureTypes.m_failuretype.NO_BUILDING_EXISTS);			
				}
			}	
			else if(condlist.get(i) instanceof ResearchCondition)
				failuretypes.add(FailureTypes.m_failuretype.NO_RESEARCH);
			else if(condlist.get(i)instanceof TimeOutCondition )
			{
				TimeOutCondition.TimeOutType type = ((TimeOutCondition) c).getType();
				List <Condition> conlist = new LinkedList<Condition>();
				if(type == TimeOutCondition.TimeOutType.start)
				{	
					p.getFailedConditions(p.getPreCondition(),condlist,gamestate);
					findfailuretype(gamestate, p,conlist,failuretypes, condtype, index);
				}
				else
				{	
					p.getFailedConditions(p.getSuccessCondition(),condlist,gamestate);
					findfailuretype(gamestate, p,conlist,failuretypes, condtype, index);		
				}
			}
			else if(c instanceof AttemptLimitCondition)
			{
				List <Condition> conlist = new LinkedList<Condition>();
				p.getFailedConditions(p.getPreCondition(),condlist,gamestate);
				findfailuretype(gamestate, p,conlist,failuretypes, condtype, index);				
			}
					
		}	

	}	
}
